{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# LSTM Sentiment Classifier"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this notebook, we use an LSTM to classify IMDB movie reviews by their sentiment."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/the-deep-learners/deep-learning-illustrated/blob/master/notebooks/lstm_sentiment_classifier.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Load dependencies"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "import keras\n",
    "from keras.datasets import imdb\n",
    "from keras.preprocessing.sequence import pad_sequences\n",
    "from keras.models import Sequential\n",
    "from keras.layers import Dense, Dropout, Embedding, SpatialDropout1D\n",
    "from keras.layers import LSTM # new! \n",
    "from keras.callbacks import ModelCheckpoint\n",
    "import os\n",
    "from sklearn.metrics import roc_auc_score \n",
    "import matplotlib.pyplot as plt \n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Set hyperparameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# output directory name:\n",
    "output_dir = 'model_output/LSTM'\n",
    "\n",
    "# training:\n",
    "epochs = 4\n",
    "batch_size = 128\n",
    "\n",
    "# vector-space embedding: \n",
    "n_dim = 64 \n",
    "n_unique_words = 10000 \n",
    "max_review_length = 100 \n",
    "pad_type = trunc_type = 'pre'\n",
    "drop_embed = 0.2 \n",
    "\n",
    "# LSTM layer architecture:\n",
    "n_lstm = 256 \n",
    "drop_lstm = 0.2\n",
    "\n",
    "# dense layer architecture: \n",
    "# n_dense = 256\n",
    "# dropout = 0.2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Load data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "(x_train, y_train), (x_valid, y_valid) = imdb.load_data(num_words=n_unique_words) # removed n_words_to_skip"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Preprocess data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_train = pad_sequences(x_train, maxlen=max_review_length, padding=pad_type, truncating=trunc_type, value=0)\n",
    "x_valid = pad_sequences(x_valid, maxlen=max_review_length, padding=pad_type, truncating=trunc_type, value=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "#### Design neural network architecture"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = Sequential()\n",
    "model.add(Embedding(n_unique_words, n_dim, input_length=max_review_length)) \n",
    "model.add(SpatialDropout1D(drop_embed))\n",
    "model.add(LSTM(n_lstm, dropout=drop_lstm))\n",
    "# model.add(Dense(n_dense, activation='relu')) \n",
    "# model.add(Dropout(dropout))\n",
    "model.add(Dense(1, activation='sigmoid'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "embedding_1 (Embedding)      (None, 100, 64)           640000    \n",
      "_________________________________________________________________\n",
      "spatial_dropout1d_1 (Spatial (None, 100, 64)           0         \n",
      "_________________________________________________________________\n",
      "lstm_1 (LSTM)                (None, 256)               328704    \n",
      "_________________________________________________________________\n",
      "dense_1 (Dense)              (None, 1)                 257       \n",
      "=================================================================\n",
      "Total params: 968,961\n",
      "Trainable params: 968,961\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model.summary() "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Configure model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "modelcheckpoint = ModelCheckpoint(filepath=output_dir+\"/weights.{epoch:02d}.hdf5\")\n",
    "if not os.path.exists(output_dir):\n",
    "    os.makedirs(output_dir)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Train!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 25000 samples, validate on 25000 samples\n",
      "Epoch 1/4\n",
      "25000/25000 [==============================] - 50s 2ms/step - loss: 0.4914 - acc: 0.7498 - val_loss: 0.3510 - val_acc: 0.8426\n",
      "Epoch 2/4\n",
      "25000/25000 [==============================] - 49s 2ms/step - loss: 0.2959 - acc: 0.8794 - val_loss: 0.3486 - val_acc: 0.8476\n",
      "Epoch 3/4\n",
      "25000/25000 [==============================] - 49s 2ms/step - loss: 0.2389 - acc: 0.9061 - val_loss: 0.3766 - val_acc: 0.8445\n",
      "Epoch 4/4\n",
      "25000/25000 [==============================] - 49s 2ms/step - loss: 0.2018 - acc: 0.9235 - val_loss: 0.3690 - val_acc: 0.8454\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<keras.callbacks.History at 0x7fc514403f98>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_valid, y_valid), callbacks=[modelcheckpoint])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "#### Evaluate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.load_weights(output_dir+\"/weights.02.hdf5\") "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_hat = model.predict_proba(x_valid)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fc51b3077b8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.hist(y_hat)\n",
    "_ = plt.axvline(x=0.5, color='orange')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'92.76'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"{:0.2f}\".format(roc_auc_score(y_valid, y_hat)*100.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
